package com.itheima.stock.servier.impl;

import com.alibaba.excel.EasyExcel;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import com.itheima.stock.mapper.StockMarketIndexInfoMapper;
import com.itheima.stock.mapper.StockRtInfoMapper;
import com.itheima.stock.pojo.dommain.InnerMarketDomain;
import com.itheima.stock.pojo.dommain.Stock4EvrDayDomain;
import com.itheima.stock.pojo.dommain.Stock4MinuteDomain;
import com.itheima.stock.pojo.dommain.StockUpdownDomain;
import com.itheima.stock.pojo.vo.StockInfoConfig;
import com.itheima.stock.servier.StockService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.vo.resp.PageResult;
import com.itheima.stock.vo.resp.R;
import com.itheima.stock.vo.resp.ResponseCode;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 股票服务实现
 */
@Service
@Slf4j
public class StockServiceImpl implements StockService {

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    @Autowired
    private Cache<String,Object> caffeineCache;

    public R<List<InnerMarketDomain>> getInnerMarket() {
        //默认从本地缓存加载数据，如果不存在则从数据库加载并同步到本地缓存
        //在开盘周期内，本地缓存默认有效期是一分钟
        R<List<InnerMarketDomain>> result= (R<List<InnerMarketDomain>>) caffeineCache.get("innerMarketKey",key ->{
            //1.获取股票最新的交易时间点（精确到分钟，秒和毫秒置为0）
            Date curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
            //modk data等后续完成job工程，再将代码删除即可 - 假数据
            //TODO mock测试数据，后期数据通过第三方接口动态获取实时数据 可删除
            curDateTime = DateTime.parse("2021-12-28 09:37:0", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

            //2.获取大盘编码集合
            List<String> mCodes = stockInfoConfig.getInner();

            //3.调用mapper查询数据
            List<InnerMarketDomain> data = stockMarketIndexInfoMapper.getMarketInfo(curDateTime, mCodes);
            //4.封装并响应
            return R.ok(data);
        });

        return result;

    }

    /**
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public R<PageResult<StockUpdownDomain>> getStockInfoByPage(Integer page, Integer pageSize) {
        //1.获取最新的股票交易点时间
        //假数据1.获取股票最新的交易时间点（精确到分钟，秒和毫秒置为0）
        Date curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //modk data等后续完成job工程，再将代码删除即可 - 假数据
        //TODO mock测试数据，后期数据通过第三方接口动态获取实时数据 可删除
        curDateTime = DateTime.parse("2021-12-28 09:37:0", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //2.设置分页PageHelper参数
        PageHelper.startPage(page, pageSize);

        //3.调用mapper查询
        List<StockUpdownDomain> pageData = stockRtInfoMapper.getStockInfoByTime(curDateTime);

        //4.组装PageResult
        PageInfo<StockUpdownDomain> PageInfo = new PageInfo<>(pageData);
        PageResult<StockUpdownDomain> pageResult = new PageResult<>(PageInfo);
        //5.响应数据
        return R.ok(pageResult);
    }

    /**
     * 显示前四条数据
     *
     * @return
     */
    @Override
    public R<List<StockUpdownDomain>> getStockInfoHome() {
        //1.获取最新的股票交易点时间
        //假数据1.获取股票最新的交易时间点（精确到分钟，秒和毫秒置为0）
        Date curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //modk data等后续完成job工程，再将代码删除即可 - 假数据
        //TODO mock测试数据，后期数据通过第三方接口动态获取实时数据 可删除
        curDateTime = DateTime.parse("2021-12-28 09:37:0", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        List<StockUpdownDomain> stockInfoHome = stockRtInfoMapper.getStockInfoHome(curDateTime);


        return R.ok(stockInfoHome);
    }


    /**
     * @return
     */
    @ApiOperation("统计每分钟的涨停跌停记录数")
    @Override
    public R<Map<String, List>> getStockUpDown() {
        //1.获取最新股票的交易时间点（截至时间）
        //1.获取最新的股票交易点时间
        //假数据1.获取股票最新的交易时间点（精确到分钟，秒和毫秒置为0）
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        // todo 假数据
        curDateTime = DateTime.parse("2022-01-06 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date endDate = curDateTime.toDate();


        //2.获取最新交易时间点对应的开盘时间点
        Date startDate = DateTimeUtil.getOpenDate(curDateTime).toDate();

        //3.统计涨停数据
        //约定mapper中flag入参： 1-》涨停数据 0：跌停
        List<Map> upList = stockRtInfoMapper.getStockUpdownCount(startDate, endDate, 1);
        //4.统计跌停数据
        List<Map> downList = stockRtInfoMapper.getStockUpdownCount(startDate, endDate, 0);

        //5.组装数据
        HashMap<String, List> info = new HashMap<>();
        info.put("upList", upList);
        info.put("downList", downList);

        //6.响应数据
        return R.ok(info);
    }

    /**
     * 导出指定页excel
     *
     * @param page     当前页面
     * @param pageSze  每页大小
     * @param response 返回头信息
     */
    @Override
    public void exportStockUpDownInfo(Integer page, Integer pageSze, HttpServletResponse response) {
        //1.获取分页数据
        R<PageResult<StockUpdownDomain>> r = this.getStockInfoByPage(page, pageSze);
        List<StockUpdownDomain> rows = r.getData().getRows();
        //2.将数据导出到excel中
        //设置响应excel文件格式类型-告诉前端我返回的是文件
        response.setContentType("application/vnd.ms-excel");
        //2.设置响应数据的编码格式
        response.setCharacterEncoding("utf-8");
        try {
            //3.设置默认的文件名称
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 stockRt默认名字
            String fileName = URLEncoder.encode("股票信息表", "UTF-8");
            //设置默认文件名称：兼容一些特殊浏览器
            response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xlsx");
            //4.响应excel流
            EasyExcel.write(response.getOutputStream(), StockUpdownDomain.class).sheet("股票信息")
                    .doWrite(rows);
        } catch (IOException e) {

            log.error("当前导出数据异常，当前页：{},每页大小：{},异常信息：{},当前时间{}", page, pageSze, e.getMessage(), DateTime.now().toString());
            //通知前端异常，稍后重试
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            R<Object> error = R.error("导出错误");
            String jsonData = null;//转为json
            try {
                jsonData = new ObjectMapper().writeValueAsString(error);
                response.getWriter().write(jsonData);
            } catch (IOException ex) {
                log.error("exportStockUpwnInfo：响应错误信息失败，时间：{}", DateTime.now().toString("yyyy-MM-dd HH:mm:Ss"));
            }

        }

    }

    @Override
    public R<Map<String, List>> getComparedSockTradeAmt() {
        //1.获取T日（最新股票交易日的日期范围）
        DateTime tEndDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //mock data
        tEndDateTime = DateTime.parse("2021-12-27 09:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date tEndDate = tEndDateTime.toDate();//jdk的date
        //开盘时间
        Date tStartDate = DateTimeUtil.getOpenDate(tEndDateTime).toDate();//年月日不变，时间改为9.30

        ////2.获取T-1日的时间范围
        DateTime preTENDateTime = DateTimeUtil.getPreviousTradingDay(tEndDateTime);
        //mock data
        preTENDateTime = DateTime.parse("2021-12-28 09:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date preTENDateDate = preTENDateTime.toDate();
        //开盘时间
        Date tPreStartDate = DateTimeUtil.getOpenDate(preTENDateTime).toDate();//年月日不变，时间改为9.30
        //3.调用mapper查询
        //3.1统计t日
        List<Map> tDate = stockMarketIndexInfoMapper.getSumAmtInfo(tStartDate, tEndDate, stockInfoConfig.getInner());
        //3.1统计t - 1日
        List<Map> preTDate = stockMarketIndexInfoMapper.getSumAmtInfo(tPreStartDate, preTENDateDate, stockInfoConfig.getInner());
        //组装数据
        HashMap<String, List> info = new HashMap<>();
        info.put("amtList", tDate);
        info.put("yesAmtList", preTDate);
        //响应
        return R.ok(info);
    }

    /**
     * 统计最新交易时间点下股票在各个涨幅区间的数量
     */
    @Override
    public R<Map> getIncreaseRangInfo() {
        //1.获取最新的交易时点
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //mock data
        curDateTime = DateTime.parse("2022-01-06 09:55:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date curDate = curDateTime.toDate();//jdk的date
        //2.调用mapper获取数据
        List<Map> infos = stockRtInfoMapper.getIncreaseRangInfoByDate(curDate);//<"title",-0.3-4>，<"count",12>

        //获取有序的标题集合 -
        List<String> upDownRange = stockInfoConfig.getUpDownRange();
        //将顺序的涨幅区间内的每个元素转化成Map对象即可
        //方式1.for循环
//        List<Map> allInfos = new ArrayList<>();
//        for (String title : upDownRange) {
//            Map tmp = null;
//            for (Map info : infos) {
//                if (info.containsValue(title)) {//是看有没有这个键 info中有没有title
//                    tmp = info;
//                    break;
//                }
//            }
//            if (tmp == null) { //mapper中没查到
//                //不存在则补齐
//                tmp = new HashMap();
//                tmp.put("count", 0);
//                tmp.put("title", title);
//            }
//            allInfos.add(tmp);
//        }

        //2.使用steam变量获取
        List<Map> allInfos = upDownRange.stream().map(title -> {
            Optional<Map> result = infos.stream().filter(map -> map.containsValue(title)).findFirst();
            if (result.isPresent()) {//判断有没有
                return result.get();
            } else {
                HashMap<String, Object> tmp = new HashMap<>();
                tmp.put("count", 0);
                tmp.put("title", title);
                return tmp;
            }
        }).collect(Collectors.toList());

        //3.组装数据
        HashMap<String, Object> data = new HashMap<>();
        data.put("time", curDateTime.toString("yyyy-MM-dd HH:mm:ss"));
        //data.put("infos", infos);
        data.put("infos", allInfos);
        return R.ok(data);
    }

    /**
     * 获取指定股票t日分时数据
     * @param stockCode
     * @return
     */
    @Override
    public R<List<Stock4MinuteDomain>> getStockScreenTimeSharing(String stockCode) {
        //1.获取T日最新股票交易时间点endTime
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());//当前时间
        endDateTime = DateTime.parse("2021-12-30 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date endDate = endDateTime.toDate();//jdk时间 - 截止时间
        Date openDate = DateTimeUtil.getOpenDate(endDateTime).toDate();//开始时间“9：30
        //2.查询
       List<Stock4MinuteDomain> data= stockRtInfoMapper.getStockInfo4minuntInfo(openDate,endDate,stockCode);
       //3.封装数据
        return R.ok(data);
    }

    /**
     * 统计指定股票的日K线数据
     * @param stockCode 股票编码
     * @return
     */
    @Override
    public R<List<Stock4EvrDayDomain>> getStockScreenDkLine(String stockCode) {
        //1.获取统计日k线的数据的时间范围
        //1.1获取截止时间
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        endDateTime = DateTime.parse("2022-01-06 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date endDate = endDateTime.toDate();//jdk
        //1.2获取起始时间
        DateTime startDateTime = endDateTime.minusMonths(2);//今天的时间减去3个月
        startDateTime = DateTime.parse("2022-01-01 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date startDate = startDateTime.toDate();//jdk
        //2.调用mapper获取指定日期范围内的日k线数据
        List<Stock4EvrDayDomain>  data = stockRtInfoMapper.getStock4DkLine(startDate,endDate,stockCode);
        //3.返回
        return R.ok(data);
    }


}


















